package xyz.lwm.lazycat.beans;

import lombok.Data;
import xyz.lwm.lazycat.utility.reflect.ReflectUtil;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * 普通方法实例化对象
 *
 * @author lwm
 */
@Data
class InstantiableWithMethod implements Instantiable {

    // method
    private final Method method;

    // target dependency
    private final Dependency targetDependency;

    // instance of self
    private Object instance;

    @Override
    public Object instantiate(Dependency[] dependsOn, BeanRefs beanRefs) {

        try {

            Object target = targetDependency.apply(beanRefs);
            Object[] args = Arrays.stream(dependsOn).map(
                    dependency -> dependency.apply(beanRefs)).toArray();
            // 缓存实例, 防止重复创建
            // 如: 创建 A 时依赖 B, B 依赖 C和 D, D 依赖 C, C 注入 B
            // A 在创建时需要先创建 B, 接着又要创建 C 和 D, 而 C 在注入 B 过程中又需要创建 B.
            // (可能实际过程复杂, 只要不出现无限循环, 最终会创建成功)
            // 等再回到 A 的创建 B 的时候, B 已经创建过了, 那么也就不需要调用 invoke 方法了
            if (instance == null) {
                instance = ReflectUtil.invoke(target, method, args);
            }
            // 第一次返回的实例是有效的，第二次返回的实例不可使用，
            // 因为第二次的实例使用不当就会覆盖第一次实例，可能出问题
            return instance;

        } catch (Throwable e) {
            throw new BeansException(e);

        }

    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof InstantiableWithMethod)) {
            return false;
        }
        InstantiableWithMethod that = (InstantiableWithMethod) obj;
        return Objects.equals(method, that.method) && Objects.equals(targetDependency, that.targetDependency);
    }

    @Override
    public String toString() {
        return targetDependency.getType().getTypeName();
    }

}
